#region Description
/*  File Name:      MeGame.cs
 *  Author:         Adam Goodchild
 *  
 *  Description:    This is the Core Minimize Engine Class
 *                  Contains all Managers and Core Features for the Minimize Engine
*/
#endregion

#region Using Statements

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using MinimizeEngine.Managers;
using MinimizeEngine.Screens;
using MinimizeEngine.Engine_Components;

#if !XBOX360
using System;
using System.Collections.Generic;
using System.Linq;
using OpiConsole;
using MinimizeEngine.Engine_Components.Console;
#endif

#endregion

namespace MinimizeEngine
{
    /// <summary>
    /// This is the Core Minimize Engine Class
    /// </summary>
    public partial class MinimizeEngine : Game
    {
        #region Fields

        #if !XBOX360
        /// <summary>
        /// Minimize Engine Form
        /// </summary>
        private static MEForm mMEForm;

        /// <summary>
        /// Console
        /// </summary>
        private static OpiConsole.Console mConsole;
        #endif

        /// <summary>
        /// Aspect Ratio of the Window
        /// </summary>
        private float mAspectRatio;

        /// <summary>
        /// Should we apply changes to the Graphics Device Manager
        /// </summary>
        private static bool mApplyChanges = false;

        /// <summary>
        /// This is the Window Title
        /// </summary>
        private static string mWindowTitle = "";

        /// <summary>
        /// This is the Default Background Color
        /// </summary>
        private static Color mBackgroundColor = Color.CornflowerBlue;

        /// <summary>
        /// This is the Graphics Device Manager
        /// </summary>
        private static GraphicsDeviceManager mGraphicsDeviceManager;

        /// <summary>
        /// This is the Content Manager for the Engine
        /// </summary>
        private static ContentManager mContentManager = null;

        /// <summary>
        /// The FPS for the Engine
        /// </summary>
        private static MEFPS mFPSComponent = null;

        /// <summary>
        /// The Screen Manager.
        /// Used to manage all Screen States
        /// </summary>
        private static MEScreenManager mScreenManager = null;

        /// <summary>
        /// The Camera Manager.
        /// Used to manage all Cameras
        /// </summary>
        private static MECameraManager mCameraManager = null;

        /// <summary>
        /// Input Manager for the Engine
        /// Handles all Input Devices:
        ///  - Keyboard
        ///  - Mouse
        ///  - Game Pad
        /// </summary>
        private static MEInputManager mInput = null;

        /// <summary>
        /// The Scene Graph Manager.
        /// Manages all Entities in the Game
        /// </summary>
        private static MESceneGraphManager mSceneGraphManager = null;

        /// <summary>
        /// The Texture Manager.
        /// Loads and Manages all Textures for the Engine.
        /// </summary>
        private static METextureManager mTextureManager = null;

        /// <summary>
        /// The Audio Manager.
        /// Loads and Manages all Audio/Sound Effects for the Engine.
        /// </summary>
        private static MEAudioManager mAudioManager = null;

        /// <summary>
        /// The Gamer Services Component.
        /// Allows for access to Services related to the Gamers and their Profiles.
        /// </summary>
        private static GamerServicesComponent mGamerServicesComponent = null;

        /// <summary>
        /// Is the Form Active
        /// </summary>
        private static bool mSceneGraphFormActive = false;

        /// <summary>
        /// Display Scene Graph Form
        /// </summary>
        private static bool mDisplaySceneGraphForm = false;

        #endregion

        #region Properties

        #if !XBOX360
        /// <summary>
        /// The Window Form attached to the Application
        /// </summary>
        public static MEForm Form
        {
            get { return mMEForm; }
            set { mMEForm = value; }
        }

        /// <summary>
        /// Get the Console
        /// </summary>
        public static OpiConsole.Console Console
        {
            get { return mConsole; }
        }
        #endif

        /// <summary>
        /// Get the Window Title
        /// </summary>
        public static string WindowTitle
        {
            get { return mWindowTitle; }
            set { mWindowTitle = value; }
        }

        /// <summary>
        /// Get or Set the Background Color
        /// </summary>
        public static Color BackgroundColor
        {
            get { return mBackgroundColor; }
            set { mBackgroundColor = value; }
        }

        /// <summary>
        /// Get the Graphics Device Manager
        /// </summary>
        public static GraphicsDeviceManager DeviceManager
        {
            get { return mGraphicsDeviceManager; }
        }

        /// <summary>
        /// Get the Content Manager
        /// </summary>
        public static ContentManager ContentManager
        {
            get { return mContentManager; }
        }

        /// <summary>
        /// Get the FPS Component
        /// </summary>
        public static MEFPS FPSComponent
        {
            get { return mFPSComponent; }
        }

        /// <summary>
        /// Get Input Manager
        /// </summary>
        public static MEInputManager Input
        {
            get { return mInput; }
        }

        /// <summary>
        /// Get the Scene Graph Manager
        /// </summary>
        public static MESceneGraphManager SceneGraphManager
        {
            get { return mSceneGraphManager; }
        }

        /// <summary>
        /// Get the Texture Manager
        /// </summary>
        public static METextureManager TextureManager
        {
            get { return mTextureManager; }
        }

        /// <summary>
        /// Get the Audio Manager
        /// </summary>
        public static MEAudioManager AudioManager
        {
            get { return mAudioManager; }
        }

        /// <summary>
        /// Is the Form Active
        /// </summary>
        public static bool SceneGraphViewerActive
        {
            get { return mSceneGraphFormActive; }
            set { mSceneGraphFormActive = value; }
        }

        /// <summary>
        /// Display Scene Graph Form
        /// </summary>
        public static bool DisplaySceneGraphForm
        {
            get { return mDisplaySceneGraphForm; }
            set { mDisplaySceneGraphForm = value; }
        }

#if !XBOX360
        /// <summary>
        /// Create and show the Form
        /// </summary>
        public static void CreateForm()
        {
            if (mMEForm == null)
            {
                mMEForm = new MEForm();
                mMEForm.BringToFront();
                mMEForm.Show();
                mSceneGraphFormActive = true;
            }
        }
#endif

        #endregion

        #region Initialization

        /// <summary>
        /// This is the Constructor for the MEGame Class.
        /// This will initialize everything to setup the Minimize Engine.
        /// It takes a width and height to setup the Games screen size.
        /// </summary>
        /// <param name="width">Width of the Game</param>
        /// <param name="height">Height of the Game</param>
        public MinimizeEngine(string windowTitle)
        {
            //Set the Window Title
            WindowTitle = windowTitle;
            this.Window.Title = windowTitle;

            //Make sure we can see the Mouse Cursor
            IsMouseVisible = true;

            //Setup the Graphics Device Manager
            mGraphicsDeviceManager = new GraphicsDeviceManager(this);

            mGraphicsDeviceManager.IsFullScreen = false;
            mGraphicsDeviceManager.ApplyChanges();

            //Setup the Screen Resolution
            ApplyScreenResChange(1024, 768);

            //Create a new Content Manager
            mContentManager = new ContentManager(this.Services);

            //Initialize the Components
            mInput = new MEInputManager(this);
            mTextureManager = new METextureManager(this);
            mSceneGraphManager = new MESceneGraphManager(this);
            mFPSComponent = new MEFPS(this);
            mCameraManager = new MECameraManager(this);
            mScreenManager = new MEScreenManager(this);
            mAudioManager = new MEAudioManager(this);
            mGamerServicesComponent = new GamerServicesComponent(this);

            //Add each Component to the Games Component List
            Components.Add(mInput);
            Components.Add(mGamerServicesComponent);
            Components.Add(mTextureManager);
            Components.Add(mSceneGraphManager);
            Components.Add(mFPSComponent);
            Components.Add(mAudioManager);
            Components.Add(mCameraManager);
            Components.Add(mScreenManager);

            #if !XBOX360
            mConsole = new OpiConsole.Console(this, MEScreenManager.SpriteBatch, null);
            mConsole.DrawConsole = false;
            mConsole.UserLevel = UsageLevel.DEBUGDEV;
            mConsole.SetTextColour(Color.Red, ConsoleLevel.NORM);

            Components.Add(mConsole);
            #endif
        }

        protected override void Initialize()
        {
            base.Initialize();

            #if !XBOX360

            if(DisplaySceneGraphForm)
            {
                CreateForm();
            }

            mGraphicsDeviceManager.DeviceReset += new System.EventHandler(GraphicsDeviceReset);
            GraphicsDeviceReset(null, EventArgs.Empty);
            #endif
        }

        public void ToggleFullScreen()
        {
            mGraphicsDeviceManager.ToggleFullScreen();
        }

        protected override void LoadContent()
        {
            base.LoadContent();

            //Load the Content for the Scene Graph
            MESceneGraphManager.LoadContent();

            #if!XBOX360
            //Load our Console Commands
            Command cmd = new Command_CreateCube();
            mConsole.RegisterCommand(cmd);
            cmd = new Command_CreateShip();
            mConsole.RegisterCommand(cmd);
            cmd = new Command_CreateSphere();
            mConsole.RegisterCommand(cmd);
            cmd = new Command_PlaySong();
            mConsole.RegisterCommand(cmd);
            cmd = new Command_PauseSong();
            mConsole.RegisterCommand(cmd);
            cmd = new Command_ResumeSong();
            mConsole.RegisterCommand(cmd);
            cmd = new Command_StopSong();
            mConsole.RegisterCommand(cmd);
            cmd = new Command_OpenForm();
            mConsole.RegisterCommand(cmd);

            //Create our CVars
            CVar_Language cvar = new CVar_Language();
            mConsole.RegisterCVar(cvar);
            #endif
        }

        #endregion

        #region Update

        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            if(DisplaySceneGraphForm)
            {
                if(!SceneGraphViewerActive)
                {
                    CreateForm();
                    SceneGraphViewerActive = true;
                }
            }

            //Set Picked Entity
            if (Input.CurrentMouseState.LeftButton == ButtonState.Pressed)
            {
                if (Input.IsCursorWithinWindowBounds())
                {
                    MESceneGraphManager.UpdateTrianglePicking();
                }
            }

            #if !XBOX360
            ViewEntityStats();
            #endif
        }

        #endregion

        #region Draw
        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            mGraphicsDeviceManager.GraphicsDevice.Clear(BackgroundColor);

            //All of the Drawing is actually handled by our Screen Manager
            base.Draw(gameTime);

            if(mApplyChanges)
            {
                mGraphicsDeviceManager.ApplyChanges();
                
                #if !XBOX360
                mConsole.RestartedDevice();
                #endif

                mApplyChanges = false;
            }
        }
        #endregion

        #region Event Handlers

        #if!XBOX360

        /// <summary>
        /// Event Handler for if the Form is Shown
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void MEFormShown(object sender, EventArgs e)
        {
            ((System.Windows.Forms.Form)sender).Hide();
        }

        /// <summary>
        /// Event Handler for if the Form is Destroyed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void MEFormHandleDestroyed(object sender, EventArgs e)
        {
            Exit();
        }

        /// <summary>
        /// Event Handler for if the Form is Shown
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void MEFormResize(object sender, EventArgs e)
        {
            ApplyScreenResChange(((MEForm)sender).Width, ((MEForm)sender).Height);
            MECameraManager.SetAllProjections(mAspectRatio);
        }

        /// <summary>
        /// Event Handler for if the Form is Shown
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void MEPanelResize(object sender, EventArgs e)
        {
            ApplyScreenResChange(((System.Windows.Forms.Panel)sender).Width, ((System.Windows.Forms.Panel)sender).Height);
            MECameraManager.SetAllProjections(mAspectRatio);
        }

        void GraphicsDeviceReset(object sender, EventArgs e)
        {
            //Update the Graphics Device Width and Height
            mAspectRatio = (float)mGraphicsDeviceManager.GraphicsDevice.Viewport.Width / (float)mGraphicsDeviceManager.GraphicsDevice.Viewport.Height;

            //Update all Cameras
            MECameraManager.SetAllProjections(mAspectRatio);
        }

        protected override void OnExiting(object sender, EventArgs args)
        {
            //Save the CVars on Exit
            //mConsole.SaveConfig();

            base.OnExiting(sender, args);
        }

        private static void ViewEntityStats()
        {
            if (MESceneGraphManager.PickedEntity != null)
            {
                if (MEEngineManager.SceneGraphViewerActive)
                {
                    Form.ViewStats(MESceneGraphManager.PickedEntity);
                }
                else
                {
                    MEEngineManager.CreateForm();
                    Form.ViewStats(MESceneGraphManager.PickedEntity);
                }
            }
        }

        #endif

        /// <summary>
        /// Apply the Screen Resolution Changes
        /// </summary>
        public static void ApplyScreenResChange(int width, int height)
        {
            int resWidth = width;
            int resHeight = height;

            if (resWidth <= 0 || resHeight <= 0)
            {
                resWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
                resHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
            }

            mGraphicsDeviceManager.PreferredBackBufferHeight = resHeight;
            mGraphicsDeviceManager.PreferredBackBufferWidth = resWidth;

            mApplyChanges = true;
        }

        #endregion
    }
}